import 'dart:ffi';

import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';


String getLibPath() {
    var libPath = "";
    if(Platform.isMacOS||Platform.isIOS){
        if(Platform.version.contains('arm64')){
            libPath="lib/native/arm64/libpsd_lib.dylib";
        }else{
            libPath="lib/native/x86/libpsd_lib.dylib";
        }
    }
    if(Platform.isWindows){
        libPath="lib/native/dll/psd_lib.dll";
    }
    if(Platform.isAndroid){
        libPath="lib/native/arm64/libpsd_lib.so";
    }
    return libPath;
}

// 定义 Dimensions 结构体
sealed class PsdInfo extends ffi.Struct {
  @ffi.Uint32()
  external int width;

  @ffi.Uint32()
  external int height;

  external Pointer<Utf8> layers;
}

// 加载动态库
final dylib = ffi.DynamicLibrary.open(getLibPath());

// 定义 get_psd_info 函数
typedef get_psd_info_func = ffi.Pointer<PsdInfo> Function(ffi.Pointer<Utf8>);
typedef GetPsdInfo = ffi.Pointer<PsdInfo> Function(ffi.Pointer<Utf8>);
final getPsdInfoByPath =
    dylib.lookupFunction<get_psd_info_func, GetPsdInfo>('get_psd_info_by_path');

// 定义 get_psd_info 函数
typedef get_psd_info_func2 = ffi.Pointer<PsdInfo> Function(
    ffi.Pointer<ffi.Uint8>, ffi.IntPtr);
typedef GetPsdInfo2 = ffi.Pointer<PsdInfo> Function(
    ffi.Pointer<ffi.Uint8>, int);
final getPsdInfoByData =
    dylib.lookupFunction<get_psd_info_func2, GetPsdInfo2>('get_psd_info_by_data');

// 定义 get_psd_image_data 函数
typedef get_psd_image_data_func = ffi.Pointer<ffi.Uint8> Function(
    ffi.Pointer<Utf8>, ffi.Pointer<ffi.Size>);
typedef GetPsdImageData = ffi.Pointer<ffi.Uint8> Function(
    ffi.Pointer<Utf8>, ffi.Pointer<ffi.Size>);
final getPsdImageDataByPath =
    dylib.lookupFunction<get_psd_image_data_func, GetPsdImageData>(
        'get_psd_image_data_by_path');

// 定义 get_psd_image_data 函数
// typedef get_psd_image_data_func2 = ffi.Pointer<ffi.Uint8> Function(
//     ffi.Pointer<ffi.Uint8>, ffi.Pointer<ffi.Size>,ffi.IntPtr);
// typedef GetPsdImageData2 = ffi.Pointer<ffi.Uint8> Function(
//     ffi.Pointer<ffi.Uint8>, ffi.Pointer<ffi.Size>,ffi.IntPtr);
typedef get_psd_image_data_func2 = ffi.Pointer<ffi.Uint8> Function(
    ffi.Pointer<ffi.Uint8>, ffi.IntPtr, ffi.Pointer<ffi.Size>);
typedef GetPsdImageData2 = ffi.Pointer<ffi.Uint8> Function(
    ffi.Pointer<ffi.Uint8>, int, ffi.Pointer<ffi.Size>);

final getPsdImageDataByData =
    dylib.lookupFunction<get_psd_image_data_func2, GetPsdImageData2>(
        'get_psd_image_data_by_data');

// 定义 free_psd_image_data 函数
typedef free_psd_image_data_func = ffi.Void Function(
    ffi.Pointer<ffi.Uint8>, ffi.IntPtr);
typedef FreePsdImageData = void Function(ffi.Pointer<ffi.Uint8>, int);
final freePsdImageData =
    dylib.lookupFunction<free_psd_image_data_func, FreePsdImageData>(
        'free_psd_image_data');


Map<String,int>? readPsdInfo({String? psdPath,Uint8List? data}){
    assert(psdPath != null || data != null, 'Either psdPath or data must be provided');
    
    var res={
        'width': 0,
        'height': 0,
    };

    if (psdPath != null) {
        final psdPathNative = psdPath.toNativeUtf8();
        final psdInfoPtr = getPsdInfoByPath(psdPathNative);
        if (psdInfoPtr != ffi.nullptr) {
            final psdInfo = psdInfoPtr.ref;
            final layersStr = psdInfo.layers.toDartString();
            calloc.free(psdPathNative);
            res["width"]=psdInfo.width;
            res["height"]=psdInfo.height;
        } else {
            print('Failed to get PSD info');
        }
    }else
    if(data!=null){
        final ffi.Pointer<ffi.Uint8> dataPtr = calloc.allocate<ffi.Uint8>(data.length);
        final ffi.Pointer<ffi.Uint8> dataTyped = dataPtr.cast<ffi.Uint8>();
        dataTyped.asTypedList(data.length).setAll(0, data);
        final psdInfoPtr = getPsdInfoByData(dataTyped, data.length);
        if (psdInfoPtr != ffi.nullptr) {
        final psdInfo = psdInfoPtr.ref;
        final layersStr = psdInfo.layers.toDartString();
        calloc.free(dataPtr);
        res["width"]=psdInfo.width;
        res["height"]=psdInfo.height;
        } else {
            print('Failed to get PSD info');
        }
    }
    return res;
}

Uint8List? readPsdImageData({String? psdPath,Uint8List? data}){
    assert(psdPath != null || data != null, 'Either psdPath or data must be provided');

    Uint8List? imageData;

    if(psdPath!=null){
        final psdPathNative = psdPath.toNativeUtf8();
        final outSize = malloc<ffi.Size>();
        final imageDataPtr = getPsdImageDataByPath(psdPathNative, outSize);
        if (imageDataPtr != ffi.nullptr) {
            final size = outSize.value;
            imageData = imageDataPtr.asTypedList(size);
            calloc.free(psdPathNative);
        } else {
            print('Failed to get PSD image data');
        }
    }else 
    if(data!=null){
        final ffi.Pointer<ffi.Uint8> dataPtr = calloc.allocate<ffi.Uint8>(data.length);
        final ffi.Pointer<ffi.Uint8> dataTyped = dataPtr.cast<ffi.Uint8>();
        dataTyped.asTypedList(data.length).setAll(0, data);
        final outSize = malloc<ffi.Size>();
        final imageDataPtr = getPsdImageDataByData(dataTyped, data.length,outSize);
        if (imageDataPtr != ffi.nullptr) {
            final size = outSize.value;
            imageData = imageDataPtr.asTypedList(size);
            calloc.free(dataPtr);
            calloc.free(outSize);
        } else {
            print('Failed to get PSD info');
        }
    }

    return imageData;
}
